/*
 *  Copyright 2008,2009 Matthieu Chase Heimer
 * 
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.

 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.

 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package com.macro10.xroads.service;

import com.macro10.switchboard.entity.Account;
import com.macro10.switchboard.service.AccountService;
import com.macro10.switchboard.service.UserTransaction;
import com.macro10.xroads.entity.Avatar;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

public class AvatarService {

    private static final Logger logger = Logger.getLogger(AvatarService.class.getPackage().getName());
    protected UserTransaction ut;
    protected EntityManager entityManager;
    protected EntityTransaction entityTransaction;

    public AvatarService(UserTransaction ut) {
        this.ut = ut;
        entityManager = ut.getEntityManager();
        entityTransaction = ut.getEntityTransaction();
    }

    public boolean doesAvatarExists(String avatarId) throws Exception {
        Avatar avatar = getAvatar(avatarId);
        if (avatar != null) {
            return true;
        } else {
            return false;
        }
    }

    public List<Avatar> getClientAvatars(String clientId) throws Exception {
        Query query = entityManager.createNamedQuery("findAvatarsByAccountId");
        query.setParameter("lowerCaseClientId", clientId.toLowerCase());
        try {
            List<Avatar> avatars = query.getResultList();
            return avatars;
        } catch (Exception e) {
            entityTransaction.setRollbackOnly();
            logger.log(Level.ERROR, "Exception in getClientAvatars(" + clientId + ")", e);
            throw new Exception("Exception in getClientAvatars(" + clientId + ")", e);
        }
    }

    public Avatar deleteAvatar(String avatarId) throws Exception {
        Query query = entityManager.createNamedQuery("findAvatarById");
        query.setParameter("lowerCaseAvatarId", avatarId.toLowerCase());
        try {
            Avatar avatar = (Avatar) query.getSingleResult();
            entityManager.remove(avatar);
            return avatar;
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            entityTransaction.setRollbackOnly();
            logger.log(Level.ERROR, "Exception in deleteAvatar(" + avatarId + ")", e);
            throw new Exception("Exception in deleteAvatar(" + avatarId + ")", e);
        }
    }

    public List<Avatar> getAllAvatars() throws Exception {
        Query query = entityManager.createNamedQuery("findAllAvatars");
        try {
            List<Avatar> aList = query.getResultList();
            return aList;
        } catch (Exception e) {
            entityTransaction.setRollbackOnly();
            logger.log(Level.ERROR, "Exception in getAllAvatars()", e);
            throw new Exception("Exception in getAllAvatars()", e);
        }
    }

    public List<Avatar> getOnlineAvatars() throws Exception {
        Query query = entityManager.createNamedQuery("findOnlineAvatars");
        query.setParameter("isOnline", true);
        try {
            List<Avatar> aList = query.getResultList();
            return aList;
        } catch (Exception e) {
            entityTransaction.setRollbackOnly();
            logger.log(Level.ERROR, "Exception in getOnlineAvatars()", e);
            throw new Exception("Exception in getOnlineAvatars()", e);
        }
    }

    public Avatar getAvatar(String avatarId) throws Exception {
        Query query = entityManager.createNamedQuery("findAvatarById");
        query.setParameter("lowerCaseAvatarId", avatarId.toLowerCase());
        try {
            Avatar avatar = (Avatar) query.getSingleResult();
            return avatar;
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            entityTransaction.setRollbackOnly();
            logger.log(Level.ERROR, "Exception in doesAvatarExist(" + avatarId + ")", e);
            throw new Exception("Exception in doesAvatarExist(" + avatarId + ")", e);
        }
    }

    /**
     * 
     * @param clientId
     * @param avatarId
     * @return null if there was no matching account was found or the avatar already exists
     * @throws java.lang.Exception
     */
    public Avatar createAvatar(String clientId, String avatarId) throws Exception {
        AccountService accountService = new AccountService(ut);
        try {
            Account account = (Account) accountService.getAccount(clientId);
            if (account == null || getAvatar(avatarId) != null) {
                return null;
            }
            Avatar avatar = new Avatar(account, avatarId);
            entityManager.persist(avatar);
            return avatar;
        }  catch (Exception e) {
            entityTransaction.setRollbackOnly();
            logger.log(Level.ERROR, "Error creating avatar: " + clientId + ", " + avatarId, e);
            throw new Exception("Error creating avatar: " + clientId + ", " + avatarId, e);
        }
    }

//    /**
//     * Moves an Avatar into an Area and runs the exit actions for the area being left and
//     * the entry actions for the area being entered. An exit action can prevent you from
//     * leaving an area if it return BaseAction.STOP_ALL.
//     *
//     * @param areaId
//     * @param doExitActions
//     * @return
//     * @throws java.lang.Exception
//     */
//    private boolean moveIntoArea(int areaId, boolean doExitActions) throws Exception {
//        XMLAction[] entryActions = new XMLAction[0];
//
//        World world = World.getInstance();
//        Area destArea = world.getAreaById(areaId);
//
//        if (destArea != null) {
//            entryActions = ActionService.getEntryActions(areaId);
//        } else {
//            return false;
//        }
//
//        if (doExitActions) {
//            XMLAction[] exitActions = new XMLAction[0];
//            //are we currently in an area?
//
//            if (area != null) {
//                exitActions = ActionService.getExitActions(getAreaId());
//            }
//
//            exitActionLoop:
//            for (int i = 0; i < exitActions.length; i++) {
//                XMLAction action = exitActions[i];
//
//                int result = ActionService.execute(action, account, this, area);
//                if (result == BaseAction.STOP) {
//                    break exitActionLoop;
//                } else if (result == BaseAction.STOP_ALL) {
//                    return false;
//                }
//            }
//        }
//
//        setAreaById(areaId);
//
//        entryActionLoop:
//        for (int i = 0; i < entryActions.length; i++) {
//            XMLAction action = entryActions[i];
//            int result = ActionService.execute(action, account, this, area);
//            if (result == BaseAction.STOP) {
//                break entryActionLoop;
//            } else if (result == BaseAction.STOP_ALL) {
//                //already in the new area, no difference between STOP & STOP_ALL
//                break entryActionLoop;
//            }
//
//        }
//        return true;
//    }
//
//    public boolean moveIntoArea(int areaId) throws Exception {
//        return moveIntoArea(areaId, true);
//    }
//
//    /**
//     * Moves an Avatar into an Area and skips the exit actions for the area being left and
//     * runs the entry actions for the area being entered.
//     */
//    public boolean jamIntoArea(int areaId) throws Exception {
//        return moveIntoArea(areaId, false);
//    }
}
